package com.demo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * NIO Socket Server
 * @author hongfeng-li
 * @date 2017年12月21日
 */
public class NioSocketServer extends Thread {

	
	private static boolean runned = false;

	private int port;
	
	public int getPort() {
		return this.port;
	}

	public void setPort(int port){
		this.port = port;
	}

	public void open() throws Exception {
		if(NioSocketServer.runned){
			System.out.println("server has opened...");
			throw new RuntimeException();
		}
		if(getPort()<=0){
			System.out.println("server port:" + getPort() + " is not right...");
			throw new RuntimeException();
		}
		NioSocketServer.runned = true;
		this.start();
	}
	
	@Override
	public void run() {
		//bossGroup线程组实际就是Acceptor线程池，负责处理客户端的TCP连接请求，如果系统只有一个服务端端口需要监听，则建议bossGroup线程组线程数设置为1
		EventLoopGroup bossGroup = new NioEventLoopGroup(1);
		
		//workerGroup是真正负责I/O读写操作的线程组，通过ServerBootstrap的group方法进行设置，用于后续的Channel绑定。
		EventLoopGroup workerGroup = new NioEventLoopGroup(8);
		
		try {
			ServerBootstrap bootstrap = new ServerBootstrap();
			bootstrap.group(bossGroup, workerGroup);
			bootstrap.channel(NioServerSocketChannel.class);
			//队列长度
			bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
			bootstrap.handler(new LoggingHandler(LogLevel.DEBUG));
			bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				public void initChannel(SocketChannel ch)
					throws Exception {
					/**
					 * 在这里ChannelPipeline是控制事件分发和传递的。
					 * 事件在管道中流转，第一站到哪，第二站到哪，到哪是终点，
					 * 就是用ChannelPipeline处理的。
					 */
					ChannelPipeline pipeline = ch.pipeline();
					pipeline.addLast(new ProtocolChannelHandler());
				}
			});
			System.out.println("start server port:{} start" + getPort());
			//绑定端口，同步等待成功
			ChannelFuture future = bootstrap.bind(getPort()).sync();
			System.out.println("start server port:{} end" + getPort());
			//等待服务端监听端口关闭
			future.channel().closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}

	public static void main(String[] args) {
		NioSocketServer server = new NioSocketServer();
		server.setPort(8090);
		server.start();
	}
}